﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace WorkItemAnalyser.Core.Assertions
{
    public class LinkAssertion : AssertionBase
    {
        public const string RuleName = "WICSA.Core.LinkRule";

        private readonly string workItemType;
        private readonly int requiredCount;
        private readonly string linkType;
        private readonly bool matchExactly;

        public LinkAssertion(string workItemType, int count, string linkType, bool matchExact)
        {
            this.workItemType = workItemType;
            requiredCount = count;
            this.linkType = linkType;
            matchExactly = matchExact;

            results = new Collection<AssertionResult>();
        }

        public string WorkItemType
        {
            get { return workItemType; }
        }

        public int Count
        {
            get { return requiredCount; }
        }

        public string LinkType
        {
            get { return linkType; }
        }

        public override IEnumerable<AssertionResult> Execute(IEnumerable<WorkItem> workItems)
        {
            foreach (var workItem in workItems)
            {
                if (workItem.Links.Count < requiredCount)
                {
                    AddResult(RuleName, 
                                        false,
                                        string.Format("Work Item {0} {1} links were expected, {2} total links found",
                                            workItem.Id, requiredCount, workItem.Links.Count));
                    continue;
                }

                var linkCount = workItem.WorkItemLinks.OfType<WorkItemLink>()
                    .Count(workItemLink => workItemLink.ArtifactLinkType != null && workItemLink.ArtifactLinkType.Name == linkType);

                if (LinkCountIsExactlyRequired(linkCount))
                {
                    AddResult(RuleName, true, string.Format("Work Item {0} {1} links of type {2} found", workItem.Id, requiredCount, linkType));
                }
                else if (LinkCountIsGreaterThanOrEqualToRequired(linkCount))
                {
                    AddResult(RuleName, true, string.Format("Work Item {0} {1} links of type {2} found", workItem.Id, requiredCount, linkType));
                }
                else
                {
                    AddResult(RuleName,
                                        false,
                                        string.Format("Work Item {0} {1} links of type {2} were expected, {3} found", workItem.Id, requiredCount,
                                                    linkType, linkCount));
                }
            }

            return results;
        }

        private bool LinkCountIsExactlyRequired(int linkCount)
        {
            return (matchExactly) && (linkCount == requiredCount);
        }

        private bool LinkCountIsGreaterThanOrEqualToRequired(int linkCount)
        {
            return (!matchExactly) && ((linkCount >= requiredCount) && (linkCount > 0));
        }
    }
}